home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / bin / DXUtils / AppWizard / DXAppwiz.awx / TEMPLATE / GDI_DLG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  81.4 KB  |  2,246 lines

  1. //-----------------------------------------------------------------------------
  2. // File: $$root$$.cpp
  3. //
  4. // Desc: DirectX MFC dialog application created by the DirectX AppWizard
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DINPUT)
  8. #define DIRECTINPUT_VERSION 0x0800
  9. $$ENDIF
  10. #include "stdafx.h"
  11. #include "$$root$$.h"
  12.  
  13.  
  14.  
  15.  
  16. //-----------------------------------------------------------------------------
  17. // MFC message maps
  18. //-----------------------------------------------------------------------------
  19. BEGIN_MESSAGE_MAP(C$$CRoot$$App, CWinApp)
  20.     //{{AFX_MSG_MAP(C$$CRoot$$App)
  21.         // NOTE - the ClassWizard will add and remove mapping macros here.
  22.         //    DO NOT EDIT what you see in these blocks of generated code!
  23.     //}}AFX_MSG
  24.     ON_COMMAND(ID_HELP, CWinApp::OnHelp)
  25. END_MESSAGE_MAP()
  26.  
  27. BEGIN_MESSAGE_MAP(C$$CRoot$$Dlg, CDialog)
  28.     //{{AFX_MSG_MAP(C$$CRoot$$Dlg)
  29.     //}}AFX_MSG_MAP
  30. END_MESSAGE_MAP()
  31.  
  32.  
  33.  
  34.  
  35. //-----------------------------------------------------------------------------
  36. // Global app and dlg
  37. //-----------------------------------------------------------------------------
  38. C$$CRoot$$App  theApp;
  39. C$$CRoot$$Dlg* g_pDlg = NULL;
  40.  
  41.  
  42.  
  43.  
  44. //-----------------------------------------------------------------------------
  45. // Name: C$$CRoot$$Dlg()
  46. // Desc: Constructor
  47. //-----------------------------------------------------------------------------
  48. C$$CRoot$$Dlg::C$$CRoot$$Dlg(CWnd* pParent /*=NULL*/)
  49.     : CDialog(C$$CRoot$$Dlg::IDD, pParent)
  50. {
  51.     //{{AFX_DATA_INIT(C$$CRoot$$Dlg)
  52.         // NOTE: the ClassWizard will add member initialization here
  53.     //}}AFX_DATA_INIT
  54.  
  55.     g_pDlg  = this;
  56.     m_hIcon = AfxGetApp()->LoadIcon(IDI_MAIN_ICON);
  57.  
  58.     m_strWindowTitle            = TEXT( "$$root$$" );
  59.     m_dwCreationWidth           = 500;
  60.     m_dwCreationHeight          = 375;
  61.     m_bLoadingApp               = TRUE;
  62.  
  63. $$IF(KEYBOARD)
  64.     m_pDI                       = NULL;
  65.     m_pKeyboard                 = NULL;
  66. $$ENDIF
  67. $$IF(ACTIONMAPPER)
  68.     m_pInputDeviceManager       = NULL;
  69. $$ENDIF
  70. $$IF(DMUSIC || DSOUND)
  71. $$IF(DMUSIC)
  72.     m_pMusicManager             = NULL;
  73.     m_pBounceSound              = NULL;
  74. $$ELSE
  75.     m_pSoundManager             = NULL;
  76.     m_pBounceSound              = NULL;
  77. $$ENDIF
  78. $$ENDIF
  79.  
  80.     ZeroMemory( &m_UserInput, sizeof(m_UserInput) );
  81.     m_fWorldRotX                = 0.0f;
  82.     m_fWorldRotY                = 0.0f;
  83. $$IF(DPLAY)
  84.  
  85.     m_pDP                       = NULL;    
  86.     m_pNetConnectWizard         = NULL;    
  87.     m_pLobbiedApp               = NULL;    
  88.     m_bWasLobbyLaunched         = FALSE;   
  89.     m_dpnidLocalPlayer          = 0;       
  90.     m_lNumberOfActivePlayers    = 0;       
  91.     m_pLocalPlayerInfo          = NULL;
  92.     m_hrNet                     = S_OK;
  93.     m_fWorldSyncTimer           = 0.0f;
  94.     m_bHostPausing              = FALSE;
  95.  
  96.     ZeroMemory( &m_PlayInfoList, sizeof(APP_PLAYER_INFO) );
  97.     m_PlayInfoList.pNext = &m_PlayInfoList;
  98.     m_PlayInfoList.pPrev = &m_PlayInfoList;
  99. $$ENDIF
  100. $$IF(DPLAYVOICE)
  101.  
  102.     m_pNetVoice                 = NULL;
  103. $$ENDIF
  104.  
  105.     // Read settings from registry
  106.     ReadSettings();
  107. }
  108.  
  109.  
  110.  
  111.  
  112. //-----------------------------------------------------------------------------
  113. // Name: OneTimeSceneInit()
  114. // Desc: Called during initial app startup, this function performs all the
  115. //       permanent initialization.
  116. //-----------------------------------------------------------------------------
  117. HRESULT C$$CRoot$$Dlg::OneTimeSceneInit()
  118. {
  119.     // TODO: perform one time initialization
  120.  
  121.     GetDlgItem(IDC_OUTPUT_LINE11)->SetWindowText( TEXT("Loading... Please wait") );
  122.  
  123. $$IF(DPLAY)
  124.     // Init COM so we can use CoCreateInstance.  And be sure to init 
  125.     // COM as multithreaded when using DirectPlay
  126.     HRESULT hr;
  127.     if( FAILED( hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) )
  128.         return hr;
  129.  
  130. $$ENDIF
  131. $$IF(DINPUT)
  132.     // Initialize DirectInput
  133.     InitInput( m_hWnd );
  134.  
  135. $$ENDIF
  136. $$IF(DMUSIC || DSOUND)
  137.     // Initialize audio
  138.     InitAudio( m_hWnd );
  139.  
  140. $$ENDIF
  141. $$IF(DPLAY)
  142.     // Initialize DirectPlay
  143.     InitDirectPlay();
  144.  
  145.     // Create a new DirectPlay session or join to an existing DirectPlay session
  146.     if( FAILED( hr = ConnectViaDirectPlay() ) )
  147.         return hr;
  148.  
  149. $$ENDIF
  150.     m_bLoadingApp = FALSE;
  151.     GetDlgItem(IDC_OUTPUT_LINE11)->SetWindowText( TEXT("") );
  152.  
  153.     return S_OK;
  154. }
  155.  
  156.  
  157.  
  158.  
  159. //-----------------------------------------------------------------------------
  160. // Name: ReadSettings()
  161. // Desc: Read the app settings from the registry
  162. //-----------------------------------------------------------------------------
  163. VOID C$$CRoot$$Dlg::ReadSettings()
  164. {
  165.     HKEY hkey;
  166.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  167.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  168.     {
  169.         // TODO: change as needed
  170.  
  171.         // Read the stored window width/height.  This is just an example,
  172.         // of how to use DXUtil_Read*() functions.
  173.         DXUtil_ReadIntRegKey( hkey, TEXT("Width"), &m_dwCreationWidth, m_dwCreationWidth );
  174.         DXUtil_ReadIntRegKey( hkey, TEXT("Height"), &m_dwCreationHeight, m_dwCreationHeight );
  175.  
  176. $$IF(DPLAY)
  177.         // Read the saved strings needed by DirectPlay
  178.         DXUtil_ReadStringRegKey( hkey, TEXT("Player Name"), 
  179.                                  m_strLocalPlayerName, MAX_PATH, TEXT("$$root$$ Player") );
  180.         DXUtil_ReadStringRegKey( hkey, TEXT("Session Name"), 
  181.                                  m_strSessionName, MAX_PATH, TEXT("$$root$$ Game") );
  182.         DXUtil_ReadStringRegKey( hkey, TEXT("Preferred Provider"), 
  183.                                  m_strPreferredProvider, MAX_PATH, 
  184.                                  TEXT("DirectPlay8 TCP/IP Service Provider") );
  185.  
  186. $$ENDIF
  187.         RegCloseKey( hkey );
  188.     }
  189. }
  190.  
  191.  
  192.  
  193.  
  194. //-----------------------------------------------------------------------------
  195. // Name: WriteSettings()
  196. // Desc: Write the app settings to the registry
  197. //-----------------------------------------------------------------------------
  198. VOID C$$CRoot$$Dlg::WriteSettings()
  199. {
  200.     HKEY hkey;
  201.     DWORD dwType = REG_DWORD;
  202.     DWORD dwLength = sizeof(DWORD);
  203.  
  204.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  205.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  206.     {
  207.         // TODO: change as needed
  208.  
  209.         // Write the window width/height.  This is just an example,
  210.         // of how to use DXUtil_Write*() functions.
  211.         DXUtil_WriteIntRegKey( hkey, TEXT("Width"), m_dwCreationWidth );
  212.         DXUtil_WriteIntRegKey( hkey, TEXT("Height"), m_dwCreationHeight );
  213.  
  214. $$IF(DPLAY)
  215.         // Save the strings used by DirectPlay that were entered via the UI
  216.         DXUtil_WriteStringRegKey( hkey, TEXT("Player Name"), m_strLocalPlayerName );
  217.         DXUtil_WriteStringRegKey( hkey, TEXT("Session Name"), m_strSessionName );
  218.         DXUtil_WriteStringRegKey( hkey, TEXT("Preferred Provider"), m_strPreferredProvider );
  219.         
  220. $$ENDIF
  221.         RegCloseKey( hkey );
  222.     }
  223. }
  224.  
  225.  
  226.  
  227.  
  228.  
  229. $$IF(ACTIONMAPPER)
  230. //-----------------------------------------------------------------------------
  231. // Name: StaticInputAddDeviceCB()
  232. // Desc: Static callback helper to call into C$$CRoot$$Dlg class
  233. //-----------------------------------------------------------------------------
  234. HRESULT CALLBACK C$$CRoot$$Dlg::StaticInputAddDeviceCB( 
  235.                                          CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  236.                                          const DIDEVICEINSTANCE* pdidi, 
  237.                                          LPVOID pParam )
  238. {
  239.     C$$CRoot$$Dlg * pApp = (C$$CRoot$$Dlg*) pParam;
  240.     return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
  241. }
  242.  
  243.  
  244.  
  245.  
  246. //-----------------------------------------------------------------------------
  247. // Name: InputAddDeviceCB()
  248. // Desc: Called from CInputDeviceManager whenever a device is added. 
  249. //       Set the dead zone, and creates a new InputDeviceState for each device
  250. //-----------------------------------------------------------------------------
  251. HRESULT C$$CRoot$$Dlg::InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  252.                                                    const DIDEVICEINSTANCE* pdidi )
  253. {
  254.     // Setup the deadzone 
  255.     DIPROPDWORD dipdw;
  256.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  257.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  258.     dipdw.diph.dwObj        = 0;
  259.     dipdw.diph.dwHow        = DIPH_DEVICE;
  260.     dipdw.dwData            = 500;
  261.     pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  262.  
  263.     // Create a new InputDeviceState for each device so the 
  264.     // app can record its state 
  265.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  266.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  267.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  268.  
  269.     return S_OK;
  270. }
  271.  
  272.  
  273.  
  274.  
  275. $$ENDIF
  276. $$IF(DINPUT)
  277. //-----------------------------------------------------------------------------
  278. // Name: InitInput()
  279. // Desc: Initialize DirectInput objects
  280. //-----------------------------------------------------------------------------
  281. HRESULT C$$CRoot$$Dlg::InitInput( HWND hWnd )
  282. {
  283.     HRESULT hr;
  284.  
  285. $$IF(KEYBOARD)
  286.     // Create a IDirectInput8*
  287.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  288.                                          IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
  289.         return DXTRACE_ERR_NOMSGBOX( "DirectInput8Create", hr );
  290.     
  291.     // Create a IDirectInputDevice8* for the keyboard
  292.     if( FAILED( hr = m_pDI->CreateDevice( GUID_SysKeyboard, &m_pKeyboard, NULL ) ) )
  293.         return DXTRACE_ERR_NOMSGBOX( "CreateDevice", hr );
  294.     
  295.     // Set the keyboard data format
  296.     if( FAILED( hr = m_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
  297.         return DXTRACE_ERR_NOMSGBOX( "SetDataFormat", hr );
  298.     
  299.     // Set the cooperative level on the keyboard
  300.     if( FAILED( hr = m_pKeyboard->SetCooperativeLevel( hWnd, 
  301.                                             DISCL_NONEXCLUSIVE | 
  302.                                             DISCL_FOREGROUND | 
  303.                                             DISCL_NOWINKEY ) ) )
  304.         return DXTRACE_ERR_NOMSGBOX( "SetCooperativeLevel", hr );
  305.  
  306.     // Acquire the keyboard
  307.     m_pKeyboard->Acquire();
  308. $$ENDIF
  309. $$IF(ACTIONMAPPER)
  310.     // Setup action format for the actual gameplay
  311.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  312.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  313.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  314.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  315.     m_diafGame.guidActionMap   = g_guidApp;
  316.  
  317.     // TODO: change the genre as needed
  318.     m_diafGame.dwGenre         = DIVIRTUAL_CAD_3DCONTROL; 
  319.  
  320.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  321.     m_diafGame.rgoAction       = g_rgGameAction;
  322.     m_diafGame.lAxisMin        = -100;
  323.     m_diafGame.lAxisMax        = 100;
  324.     m_diafGame.dwBufferSize    = 16;
  325.     _tcscpy( m_diafGame.tszActionMap, _T("$$root$$ Game") );
  326.  
  327.     // Create a new input device manager
  328.     m_pInputDeviceManager = new CInputDeviceManager();
  329.  
  330.     if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame, 
  331.                                                     StaticInputAddDeviceCB, this ) ) )
  332.         return DXTRACE_ERR_NOMSGBOX( "m_pInputDeviceManager->Create", hr );
  333. $$ENDIF
  334.  
  335.     return S_OK;
  336. }
  337.  
  338.  
  339.  
  340.  
  341. $$ENDIF
  342. $$IF(DMUSIC || DSOUND)
  343. //-----------------------------------------------------------------------------
  344. // Name: InitAudio()
  345. // Desc: Initialize DirectX audio objects
  346. //-----------------------------------------------------------------------------
  347. HRESULT C$$CRoot$$Dlg::InitAudio( HWND hWnd )
  348. {
  349.     HRESULT hr;
  350.  
  351. $$IF(DMUSIC)
  352.     // Create the music manager class, used to create the sounds
  353.     m_pMusicManager = new CMusicManager();
  354.     if( FAILED( hr = m_pMusicManager->Initialize( hWnd ) ) )
  355.         return DXTRACE_ERR_NOMSGBOX( "m_pMusicManager->Initialize", hr );
  356.  
  357.     // Instruct the music manager where to find the files
  358.     // TODO: Set this to the media directory, or use resources
  359.     TCHAR szPath[MAX_PATH];
  360.     GetCurrentDirectory( MAX_PATH, szPath ); 
  361.     m_pMusicManager->SetSearchDirectory( szPath );
  362.  
  363.     // TODO: load the sounds from resources (or files)
  364.     m_pMusicManager->CreateSegmentFromResource( &m_pBounceSound, _T("BOUNCE"), _T("WAVE") );
  365.  
  366. $$ELSE
  367.     // Create a static IDirectSound in the CSound class.  
  368.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  369.     // format to stereo, 22kHz and 16-bit output.
  370.     m_pSoundManager = new CSoundManager();
  371.  
  372.     if( FAILED( hr = m_pSoundManager->Initialize( hWnd, DSSCL_PRIORITY, 2, 22050, 16 ) ) )
  373.         return DXTRACE_ERR_NOMSGBOX( TEXT("m_pSoundManager->Initialize"), hr );
  374.  
  375.     // TODO: load the sounds from resources (or files)
  376.     m_pSoundManager->Create( &m_pBounceSound, TEXT("BOUNCE"), 0, GUID_NULL, 5 );
  377.  
  378. $$ENDIF
  379.     return S_OK;
  380. }
  381.  
  382.  
  383.  
  384.  
  385. $$ENDIF
  386. $$IF(DPLAY)
  387. //-----------------------------------------------------------------------------
  388. // Name: InitDirectPlay()
  389. // Desc: Initialize DirectPlay
  390. //-----------------------------------------------------------------------------
  391. HRESULT C$$CRoot$$Dlg::InitDirectPlay()
  392. {
  393.     // Initialize critical sections
  394.     InitializeCriticalSection( &g_csPlayerContext );
  395.     InitializeCriticalSection( &g_csWorldStateContext );
  396.  
  397.     // Create helper class
  398.     m_pNetConnectWizard = new CNetConnectWizard( AfxGetInstanceHandle(), m_hWnd, 
  399.                                                  m_strWindowTitle, &g_guidApp );
  400. $$IF(DPLAYVOICE)
  401.     m_pNetVoice         = new CNetVoice( StaticDirectPlayVoiceClientMessageHandler, StaticDirectPlayVoiceServerMessageHandler );
  402. $$ENDIF
  403.  
  404.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  405.     HRESULT hr;
  406.  
  407.     // Create IDirectPlay8Peer
  408.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  409.                                        CLSCTX_INPROC_SERVER,
  410.                                        IID_IDirectPlay8Peer, 
  411.                                        (LPVOID*) &m_pDP ) ) )
  412.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  413.  
  414.     // Create IDirectPlay8LobbiedApplication
  415.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  416.                                        CLSCTX_INPROC_SERVER,
  417.                                        IID_IDirectPlay8LobbiedApplication, 
  418.                                        (LPVOID*) &m_pLobbiedApp ) ) )
  419.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  420.  
  421.     // Init the helper class, now that m_pDP and m_pLobbiedApp are valid
  422.     m_pNetConnectWizard->Init( m_pDP, m_pLobbiedApp );
  423.  
  424.     // Init IDirectPlay8Peer
  425.     if( FAILED( hr = m_pDP->Initialize( NULL, StaticDirectPlayMessageHandler, 0 ) ) )
  426.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  427.  
  428.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  429.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  430.     // so be prepared ahead of time.
  431.     if( FAILED( hr = m_pLobbiedApp->Initialize( NULL, StaticDirectPlayLobbyMessageHandler, 
  432.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  433.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  434.  
  435.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connection
  436.     // if we have been lobby launched.  Initialize is guaranteed to return after 
  437.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  438.     // multiple lobby connections, we do not need to remember the lobby connection
  439.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  440.     m_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  441.  
  442.     return S_OK;
  443. }
  444.  
  445.  
  446.  
  447.  
  448. //-----------------------------------------------------------------------------
  449. // Name: ConnectViaDirectPlay()
  450. // Desc: Create a new DirectPlay session or join to an existing DirectPlay session
  451. //-----------------------------------------------------------------------------
  452. HRESULT C$$CRoot$$Dlg::ConnectViaDirectPlay()
  453. {
  454.     HRESULT hr;
  455.     BOOL bWasFullscreen  = FALSE;
  456.     BOOL bConnectSuccess = FALSE;
  457.  
  458.     // If we were launched from a lobby client, then we may have connection settings
  459.     // that we can use either host or join a game.  If not, then we'll need to prompt 
  460.     // the user to determine how to connect.
  461.     if( m_bWasLobbyLaunched && m_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  462.     {
  463.         // If were lobby launched then the DPL_MSGID_CONNECT has already been
  464.         // handled, and since the lobby client also sent us connection settings
  465.         // we can use them to either host or join a DirectPlay session. 
  466.         if( FAILED( hr = m_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  467.         {
  468.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  469.             MessageBox( TEXT("Failed to connect using lobby settings. ")
  470.                         TEXT("The sample will now quit."),
  471.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  472.  
  473.             bConnectSuccess = FALSE;
  474.         }
  475.         else
  476.         {
  477.             // Read information from m_pNetConnectWizard
  478.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  479.  
  480.             bConnectSuccess = TRUE; 
  481.         }
  482.     }
  483.     else
  484.     {
  485.         // If not lobby launched, prompt the user about the network 
  486.         // connection and which session they would like to join or 
  487.         // if they want to create a new one.
  488.  
  489.         // Setup connection wizard
  490.         m_pNetConnectWizard->SetPlayerName( m_strLocalPlayerName );
  491.         m_pNetConnectWizard->SetSessionName( m_strSessionName );
  492.         m_pNetConnectWizard->SetPreferredProvider( m_strPreferredProvider );
  493.  
  494.         // Start a connection wizard.  The wizard uses GDI dialog boxes.
  495.         // More complex games can use this as a starting point and add a 
  496.         // fancier graphics layer such as Direct3D.
  497.         hr = m_pNetConnectWizard->DoConnectWizard( FALSE );        
  498.         if( FAILED( hr ) ) 
  499.         {
  500.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  501.             MessageBox( TEXT("Multiplayer connect failed. ")
  502.                         TEXT("The sample will now quit."),
  503.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  504.             bConnectSuccess = FALSE;
  505.         } 
  506.         else if( hr == NCW_S_QUIT ) 
  507.         {
  508.             // The user canceled the Multiplayer connect
  509.             bConnectSuccess = FALSE;
  510.         }
  511.         else
  512.         {
  513.             bConnectSuccess = TRUE; 
  514.  
  515.             // Read information from m_pNetConnectWizard
  516.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  517.             _tcscpy( m_strSessionName, m_pNetConnectWizard->GetSessionName() );
  518.             _tcscpy( m_strPreferredProvider, m_pNetConnectWizard->GetPreferredProvider() );
  519.  
  520.             // Write information to the registry
  521.             WriteSettings();
  522.         }
  523.     }
  524.  
  525. $$IF(DPLAYVOICE)
  526.     if( bConnectSuccess )
  527.     {
  528.         // Initialize DirectPlay voice
  529.         if( FAILED( hr = InitDirectPlayVoice() ) )
  530.         {
  531.             bConnectSuccess = FALSE;
  532.  
  533.             if( hr == DVERR_USERBACK )
  534.             {
  535.                 MessageBox( TEXT("The user backed out of the wizard.  ")
  536.                             TEXT("This simple sample does not handle this case, so ")
  537.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  538.             }
  539.             else if( hr == DVERR_USERCANCEL )
  540.             {
  541.                 MessageBox( TEXT("The user canceled the wizard. ")
  542.                             TEXT("This simple sample does not handle this case, so ")
  543.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  544.             }
  545.             else 
  546.             {
  547.                 DXTRACE_ERR( TEXT("m_pNetVoice->Init"), hr );
  548.             }
  549.         }
  550.  
  551.         if( m_pNetVoice->IsHalfDuplex() ) 
  552.         {
  553.             MessageBox(  TEXT("You are running in half duplex mode. ")
  554.                         TEXT("In half duplex mode no recording takes place."), 
  555.                         TEXT("blank"), MB_OK );
  556.         }
  557.     }
  558.  
  559. $$ENDIF
  560.     if( FALSE == bConnectSuccess )
  561.     {
  562.         // Quit the app
  563.         PostQuitMessage(0);
  564.     }
  565.  
  566.     return S_OK;
  567. }
  568.  
  569.  
  570.  
  571.  
  572. $$ENDIF
  573. $$IF(DPLAYVOICE)
  574. //-----------------------------------------------------------------------------
  575. // Name: InitDirectPlayVoice()
  576. // Desc: Init DirectPlay Voice
  577. //-----------------------------------------------------------------------------
  578. HRESULT C$$CRoot$$Dlg::InitDirectPlayVoice()
  579. {
  580.     HRESULT hr;
  581.  
  582.     // Set default DirectPlayVoice setup options
  583.     // TODO: change as needed or ask user for settings
  584.     ZeroMemory( &m_dvClientConfig, sizeof(m_dvClientConfig) );
  585.     m_dvClientConfig.dwSize                 = sizeof(m_dvClientConfig);
  586.     m_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  587.                                               DVCLIENTCONFIG_AUTORECORDVOLUME;
  588.     m_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  589.     m_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  590.     m_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  591.     m_dvClientConfig.dwThreshold            = DVTHRESHOLD_UNUSED;
  592.     m_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  593.     m_dvClientConfig.dwNotifyPeriod         = 0;
  594.  
  595.     m_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  596.  
  597.     // Creates and connects to DirectPlay Voice using the settings stored 
  598.     // in m_guidDVSessionCT & m_dvClientConfig.  It also runs the DirectPlay
  599.     // Voice wizard if it hasn't been run before on this machine
  600.     if( FAILED( hr = m_pNetVoice->Init( m_hWnd, m_pNetConnectWizard->IsHostPlayer(), TRUE,
  601.                                         m_pDP, DVSESSIONTYPE_PEER, 
  602.                                         &m_guidDVSessionCT, &m_dvClientConfig ) ) )
  603.         return hr;
  604.  
  605.     return S_OK;
  606. }
  607.  
  608.  
  609.  
  610.  
  611. $$ENDIF
  612. //-----------------------------------------------------------------------------
  613. // Name: FrameMove()
  614. // Desc: Called once per frame, the call is the entry point for animating
  615. //       the scene.
  616. //-----------------------------------------------------------------------------
  617. HRESULT C$$CRoot$$Dlg::FrameMove()
  618. {
  619.     // TODO: update world
  620.  
  621.     // Update user input state
  622.     UpdateInput( &m_UserInput );
  623.  
  624. $$IF(DPLAY)
  625.     // Send local input to all network players if it changed
  626.     SendLocalInputIfChanged();
  627.  
  628.     if( m_pNetConnectWizard->IsHostPlayer() )
  629.     {
  630.         m_fWorldSyncTimer -= m_fElapsedTime;
  631.         if( m_fWorldSyncTimer < 0.0f )
  632.         {
  633.             // If this player is the host and timer has expired
  634.             // then reset timer and send the world state to all players
  635.             m_fWorldSyncTimer = 0.1f;
  636.             SendWorldStateToAll();
  637.         }
  638.     }
  639.  
  640. $$ENDIF
  641. $$IF(ACTIONMAPPER)
  642.     // Respond to input
  643.     if( m_UserInput.bDoConfigureInput )
  644.     {
  645.         // One-shot per keypress
  646.         m_UserInput.bDoConfigureInput = FALSE;
  647.  
  648.         Pause( TRUE );
  649.  
  650.         // Get access to the list of semantically-mapped input devices
  651.         // to delete all InputDeviceState structs before calling ConfigureDevices()
  652.         CInputDeviceManager::DeviceInfo* pDeviceInfos;
  653.         DWORD dwNumDevices;
  654.         m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  655.  
  656.         for( DWORD i=0; i<dwNumDevices; i++ )
  657.         {
  658.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  659.             SAFE_DELETE( pInputDeviceState );
  660.             pDeviceInfos[i].pParam = NULL;
  661.         }
  662.  
  663.         // Configure the devices (with edit capability)
  664.         m_pInputDeviceManager->ConfigureDevices( m_hWnd, NULL, NULL, DICD_EDIT, NULL );
  665.  
  666.         Pause( FALSE );
  667.     }
  668.  
  669. $$ENDIF
  670. $$IF(DPLAYVOICE)
  671.     if( m_UserInput.bDoConfigureVoice )
  672.     {
  673.         // One-shot per keypress
  674.         m_UserInput.bDoConfigureVoice = FALSE;
  675.  
  676.         Pause(TRUE);
  677.  
  678.         // Allow user to configure the voice settings
  679.         UserConfigVoice();
  680.  
  681.         Pause(FALSE);
  682.     }
  683.  
  684. $$ENDIF
  685. $$IF(DPLAY)
  686.     // Combining the input data from all players 
  687.     // TODO: Combining the input data from all players is an unrealistic yet simple 
  688.     //       usage of network data. Use it as a starting point to serve your needs
  689.     CombineInputFromAllPlayers( &m_CombinedNetworkInput );
  690.  
  691. $$ENDIF
  692. $$IF(DPLAYVOICE)
  693.     // Update talking varibles 
  694.     // TODO: The talking variables just update the text, but something more complex
  695.     //       like animation could be done based on them
  696.     UpdateTalkingVariables();
  697.  
  698. $$ENDIF
  699.     // Update the world state according to user input
  700.  
  701. $$IF(DPLAY)
  702.     // Enter world state critical section before accessing world state data 
  703.     // otherwise one of the DirectPlay threads may change the data
  704.     // while this thread is accessing or changing it.
  705.     WORLD_LOCK();
  706.  
  707.     // Rotate object according to user input from all network players
  708.     // Only update the world state if the host hasn't told our to pause
  709.     if( FALSE == m_bHostPausing )
  710.     {
  711.         // Update the m_fWorldRotY & m_fWorldRotX according 
  712.         // to the combined input of all the network players
  713. $$IF(ACTIONMAPPER)
  714.         if( m_CombinedNetworkInput.fAxisRotateLR )
  715.             m_fWorldRotY += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateLR;
  716.  
  717.         if( m_CombinedNetworkInput.fAxisRotateUD )
  718.             m_fWorldRotX += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateUD;
  719. $$ELSE // start !ACTIONMAPPER
  720.         if( m_CombinedNetworkInput.bRotateLeft && !m_CombinedNetworkInput.bRotateRight )
  721.             m_fWorldRotY += m_fElapsedTime;
  722.         else if( m_CombinedNetworkInput.bRotateRight && !m_CombinedNetworkInput.bRotateLeft )
  723.             m_fWorldRotY -= m_fElapsedTime;
  724.  
  725.         if( m_CombinedNetworkInput.bRotateUp && !m_CombinedNetworkInput.bRotateDown )
  726.             m_fWorldRotX += m_fElapsedTime;
  727.         else if( m_CombinedNetworkInput.bRotateDown && !m_CombinedNetworkInput.bRotateUp )
  728.             m_fWorldRotX -= m_fElapsedTime;
  729. $$ENDIF // end ACTIONMAPPER
  730.     }
  731.  
  732.     // Leave the critical section
  733.     WORLD_UNLOCK();
  734.  
  735. $$ENDIF // end DPLAY
  736. $$IF(!DPLAY)
  737. $$IF(ACTIONMAPPER)
  738.     if( m_UserInput.fAxisRotateLR )
  739.         m_fWorldRotY += m_fElapsedTime * m_UserInput.fAxisRotateLR;
  740.  
  741.     if( m_UserInput.fAxisRotateUD )
  742.         m_fWorldRotX += m_fElapsedTime * m_UserInput.fAxisRotateUD;
  743.  
  744. $$ELSE // start !ACTIONMAPPER
  745.     if( m_UserInput.bRotateLeft && !m_UserInput.bRotateRight )
  746.         m_fWorldRotY += m_fElapsedTime;
  747.     else if( m_UserInput.bRotateRight && !m_UserInput.bRotateLeft )
  748.         m_fWorldRotY -= m_fElapsedTime;
  749.  
  750.     if( m_UserInput.bRotateUp && !m_UserInput.bRotateDown )
  751.         m_fWorldRotX += m_fElapsedTime;
  752.     else if( m_UserInput.bRotateDown && !m_UserInput.bRotateUp )
  753.         m_fWorldRotX -= m_fElapsedTime;
  754.  
  755. $$ENDIF // end ACTIONMAPPER
  756. $$ENDIF // end !DPLAY
  757. $$IF(DMUSIC || DSOUND)
  758.     // Play the sound every so often while the button is pressed 
  759.     if( m_UserInput.bPlaySoundButtonDown )
  760.     {
  761.         m_fSoundPlayRepeatCountdown -= m_fElapsedTime;
  762.         if( m_fSoundPlayRepeatCountdown <= 0.0f )
  763.         {
  764.             m_fSoundPlayRepeatCountdown = 0.5f;
  765.             if( m_pBounceSound )
  766.                 m_pBounceSound->Play();
  767.         }
  768.     }
  769.     else
  770.     {
  771.         m_fSoundPlayRepeatCountdown = 0.0f;
  772.     }
  773.  
  774. $$ENDIF // DMUSIC || DSOUND
  775.     return S_OK;
  776. }
  777.  
  778.  
  779.  
  780.  
  781. //-----------------------------------------------------------------------------
  782. // Name: UpdateInput()
  783. // Desc: Update the user input.  Called once per frame 
  784. //-----------------------------------------------------------------------------
  785. void C$$CRoot$$Dlg::UpdateInput( UserInput* pUserInput )
  786. {
  787. $$IF(ACTIONMAPPER)
  788.     if( NULL == m_pInputDeviceManager )
  789.         return;
  790.  
  791.     // Get access to the list of semantically-mapped input devices
  792.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  793.     DWORD dwNumDevices;
  794.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  795.  
  796.     // Loop through all devices and check game input
  797.     for( DWORD i=0; i<dwNumDevices; i++ )
  798.     {
  799.         DIDEVICEOBJECTDATA rgdod[10];
  800.         DWORD   dwItems = 10;
  801.         HRESULT hr;
  802.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  803.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  804.  
  805.         hr = pdidDevice->Acquire();
  806.         hr = pdidDevice->Poll();
  807.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  808.                                         rgdod, &dwItems, 0 );
  809.         if( FAILED(hr) )
  810.             continue;
  811.  
  812.         // Get the sematics codes for the game menu
  813.         for( DWORD j=0; j<dwItems; j++ )
  814.         {
  815.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  816.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  817.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/100.0f;
  818.  
  819.             switch( rgdod[j].uAppData )
  820.             {
  821.                 // TODO: Handle semantics for the game 
  822.  
  823.                 // Handle relative axis data
  824.                 case INPUT_ROTATE_AXIS_LR: 
  825.                     pInputDeviceState->fAxisRotateLR = -fAxisState;
  826.                     break;
  827.                 case INPUT_ROTATE_AXIS_UD:
  828.                     pInputDeviceState->fAxisRotateUD = -fAxisState;
  829.                     break;
  830.  
  831.                 // Handle buttons separately so the button state data
  832.                 // doesn't overwrite the axis state data, and handle
  833.                 // each button separately so they don't overwrite each other
  834.                 case INPUT_ROTATE_LEFT:  pInputDeviceState->bButtonRotateLeft  = bButtonState; break;
  835.                 case INPUT_ROTATE_RIGHT: pInputDeviceState->bButtonRotateRight = bButtonState; break;
  836.                 case INPUT_ROTATE_UP:    pInputDeviceState->bButtonRotateUp    = bButtonState; break;
  837.                 case INPUT_ROTATE_DOWN:  pInputDeviceState->bButtonRotateDown  = bButtonState; break;
  838. $$IF(DMUSIC || DSOUND)
  839.                 case INPUT_PLAY_SOUND:   pInputDeviceState->bButtonPlaySoundButtonDown = bButtonState; break;
  840. $$ENDIF // DMUSIC || DSOUND
  841.  
  842.                 // Handle one-shot buttons
  843.                 case INPUT_CONFIG_INPUT:   if( bButtonState ) pUserInput->bDoConfigureInput = TRUE; break;
  844. $$IF(DPLAYVOICE)
  845.                 case INPUT_CONFIG_VOICE:   if( bButtonState ) pUserInput->bDoConfigureVoice   = TRUE; break;
  846. $$ENDIF
  847.             }
  848.         }
  849.     }
  850.  
  851.     // TODO: change process code as needed
  852.  
  853.     // Process user input and store result into pUserInput struct
  854.     pUserInput->fAxisRotateLR = 0.0f;
  855.     pUserInput->fAxisRotateUD = 0.0f;
  856. $$IF(DMUSIC || DSOUND)
  857.     pUserInput->bPlaySoundButtonDown = FALSE;
  858. $$ENDIF
  859.  
  860.     // Concatinate the data from all the DirectInput devices
  861.     for( i=0; i<dwNumDevices; i++ )
  862.     {
  863.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  864.  
  865.         // Use the axis data that is furthest from zero
  866.         if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
  867.             pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  868.  
  869.         if( fabs(pInputDeviceState->fAxisRotateUD) > fabs(pUserInput->fAxisRotateUD) )
  870.             pUserInput->fAxisRotateUD = pInputDeviceState->fAxisRotateUD;
  871.  
  872.         // Process the button data 
  873.         if( pInputDeviceState->bButtonRotateLeft )
  874.             pUserInput->fAxisRotateLR = 1.0f;
  875.         else if( pInputDeviceState->bButtonRotateRight )
  876.             pUserInput->fAxisRotateLR = -1.0f;
  877.  
  878.         if( pInputDeviceState->bButtonRotateUp )
  879.             pUserInput->fAxisRotateUD = 1.0f;
  880.         else if( pInputDeviceState->bButtonRotateDown )
  881.             pUserInput->fAxisRotateUD = -1.0f;
  882.  
  883. $$IF(DMUSIC || DSOUND)
  884.         if( pInputDeviceState->bButtonPlaySoundButtonDown )
  885.             pUserInput->bPlaySoundButtonDown = TRUE;
  886. $$ENDIF // DMUSIC || DSOUND
  887.     } 
  888. $$ENDIF // ACTIONMAPPER
  889. $$IF(KEYBOARD)
  890.     HRESULT hr;
  891.  
  892.     // Get the input's device state, and put the state in dims
  893.     ZeroMemory( &pUserInput->diks, sizeof(pUserInput->diks) );
  894.     hr = m_pKeyboard->GetDeviceState( sizeof(pUserInput->diks), &pUserInput->diks );
  895.     if( FAILED(hr) ) 
  896.     {
  897.         m_pKeyboard->Acquire();
  898.         return; 
  899.     }
  900.  
  901.     // TODO: Process user input as needed
  902.     pUserInput->bRotateLeft  = ( (pUserInput->diks[DIK_LEFT] & 0x80)  == 0x80 );
  903.     pUserInput->bRotateRight = ( (pUserInput->diks[DIK_RIGHT] & 0x80) == 0x80 );
  904.     pUserInput->bRotateUp    = ( (pUserInput->diks[DIK_UP] & 0x80)    == 0x80 );
  905.     pUserInput->bRotateDown  = ( (pUserInput->diks[DIK_DOWN] & 0x80)  == 0x80 );
  906. $$IF(DMUSIC || DSOUND)
  907.     pUserInput->bPlaySoundButtonDown   = ( (pUserInput->diks[DIK_F5] & 0x80)     == 0x80 );
  908. $$ENDIF // DMUSIC || DSOUND
  909. $$ENDIF // KEYBOARD
  910. $$IF(!DINPUT)
  911.     pUserInput->bRotateUp    = ( m_bHasFocus && (GetAsyncKeyState( VK_UP )    & 0x8000) == 0x8000 );
  912.     pUserInput->bRotateDown  = ( m_bHasFocus && (GetAsyncKeyState( VK_DOWN )  & 0x8000) == 0x8000 );
  913.     pUserInput->bRotateLeft  = ( m_bHasFocus && (GetAsyncKeyState( VK_LEFT )  & 0x8000) == 0x8000 );
  914.     pUserInput->bRotateRight = ( m_bHasFocus && (GetAsyncKeyState( VK_RIGHT ) & 0x8000) == 0x8000 );
  915. $$IF(DMUSIC || DSOUND)
  916.     pUserInput->bPlaySoundButtonDown = ( m_bHasFocus && (GetAsyncKeyState( VK_F5 ) & 0x8000) == 0x8000 );
  917. $$ENDIF // DMUSIC || DSOUND
  918. $$ENDIF // !DINPUT
  919. }
  920.  
  921.  
  922.  
  923.  
  924. $$IF(DPLAY)
  925. //-----------------------------------------------------------------------------
  926. // Name: SendLocalInputIfChanged()
  927. // Desc: Send local input to all network players if it changed
  928. //-----------------------------------------------------------------------------
  929. HRESULT C$$CRoot$$Dlg::SendLocalInputIfChanged()
  930. {
  931.     if( NULL == m_pLocalPlayerInfo )
  932.         return S_OK;
  933.  
  934.     // Enter player critical section before accessing player's state data 
  935.     // otherwise the DirectPlay network threads may change the data
  936.     // while this thread is accessing it.
  937.     PLAYER_LOCK();                  
  938.  
  939.     // Compare the local input axis data from DirectInput against the 
  940.     // state of the axis data stored in the local player's 
  941.     // APP_PLAYER_INFO struct to see if input changed
  942.     BOOL bLocalInputChanged = FALSE;
  943. $$IF(ACTIONMAPPER)
  944.     if( m_UserInput.fAxisRotateLR != m_pLocalPlayerInfo->fAxisRotateLR ||
  945.         m_UserInput.fAxisRotateUD != m_pLocalPlayerInfo->fAxisRotateUD )
  946. $$ELSE
  947.     if( m_UserInput.bRotateUp    != m_pLocalPlayerInfo->bRotateUp   ||
  948.         m_UserInput.bRotateDown  != m_pLocalPlayerInfo->bRotateDown ||
  949.         m_UserInput.bRotateLeft  != m_pLocalPlayerInfo->bRotateLeft ||
  950.         m_UserInput.bRotateRight != m_pLocalPlayerInfo->bRotateRight )
  951. $$ENDIF
  952.     {
  953.         bLocalInputChanged = TRUE;
  954.     }
  955.  
  956.     PLAYER_UNLOCK();                // leave player context CS
  957.  
  958.     // If it has changed then send it to all the network players
  959.     // including the local player
  960.     if( bLocalInputChanged )
  961.     {
  962.         GAMEMSG_INPUTSTATE msgInputState;
  963.         msgInputState.nType = GAME_MSGID_INPUTSTATE;
  964. $$IF(ACTIONMAPPER)
  965.         msgInputState.fAxisRotateLR = m_UserInput.fAxisRotateLR;
  966.         msgInputState.fAxisRotateUD = m_UserInput.fAxisRotateUD;
  967. $$ELSE
  968.         msgInputState.bRotateUp    = m_UserInput.bRotateUp;
  969.         msgInputState.bRotateDown  = m_UserInput.bRotateDown;
  970.         msgInputState.bRotateLeft  = m_UserInput.bRotateLeft;
  971.         msgInputState.bRotateRight = m_UserInput.bRotateRight;
  972. $$ENDIF
  973.  
  974.         DPN_BUFFER_DESC bufferDesc;
  975.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_INPUTSTATE);
  976.         bufferDesc.pBufferData  = (BYTE*) &msgInputState;
  977.  
  978.         // Send it to all of the players including the local client
  979.         // DirectPlay will tell via the message handler 
  980.         // if there are any severe errors, so ignore any errors 
  981.         DPNHANDLE hAsync;
  982.         m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  983.                        0, NULL, &hAsync, DPNSEND_GUARANTEED );
  984.     }
  985.  
  986.  
  987.     return S_OK;
  988. }
  989.  
  990.  
  991.  
  992.  
  993. //-----------------------------------------------------------------------------
  994. // Name: SendWorldStateToAll()
  995. // Desc: Send the world state to all players on the network
  996. //-----------------------------------------------------------------------------
  997. HRESULT C$$CRoot$$Dlg::SendWorldStateToAll()
  998. {
  999.     // Enter world state critical section before accessing world state data 
  1000.     // otherwise one of the DirectPlay threads may change the data
  1001.     // while this thread is accessing it.
  1002.     WORLD_LOCK();
  1003.  
  1004.     GAMEMSG_WORLDSTATE msgWorldState;
  1005.     msgWorldState.nType = GAME_MSGID_WORLDSTATE;
  1006.     msgWorldState.fWorldRotX = m_fWorldRotX;
  1007.     msgWorldState.fWorldRotY = m_fWorldRotY;
  1008.  
  1009.     // Leave the critical section
  1010.     WORLD_UNLOCK();
  1011.  
  1012.     DPN_BUFFER_DESC bufferDesc;
  1013.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_WORLDSTATE);
  1014.     bufferDesc.pBufferData  = (BYTE*) &msgWorldState;
  1015.  
  1016.     // Send the message to all the players except the ourselves
  1017.     // DirectPlay will tell via the message handler 
  1018.     // if there are any severe errors, so ignore any errors 
  1019.     DPNHANDLE hAsync;
  1020.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1021.                    0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  1022.  
  1023.     return S_OK;
  1024. }
  1025.  
  1026.  
  1027.  
  1028.  
  1029. //-----------------------------------------------------------------------------
  1030. // Name: SendPauseMessageToAll()
  1031. // Desc: Send a pause message to all players on the network
  1032. //-----------------------------------------------------------------------------
  1033. HRESULT C$$CRoot$$Dlg::SendPauseMessageToAll( BOOL bPause )
  1034. {
  1035.     GAMEMSG_HOSTPAUSE msgPause;
  1036.     msgPause.nType = GAME_MSGID_HOSTPAUSE;
  1037.     msgPause.bHostPause = bPause; 
  1038.  
  1039.     DPN_BUFFER_DESC bufferDesc;
  1040.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_HOSTPAUSE);
  1041.     bufferDesc.pBufferData  = (BYTE*) &msgPause;
  1042.  
  1043.     // Send the message to all the players except the ourselves
  1044.     // DirectPlay will tell via the message handler 
  1045.     // if there are any severe errors, so ignore any errors 
  1046.     DPNHANDLE hAsync;
  1047.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1048.                    0, NULL, &hAsync, DPNSEND_GUARANTEED | DPNSEND_NOLOOPBACK );
  1049.  
  1050.     return S_OK;
  1051. }
  1052.  
  1053.  
  1054.  
  1055.  
  1056. $$IF(ACTIONMAPPER)
  1057. //-----------------------------------------------------------------------------
  1058. // Name: CombineInputFromAllPlayers()
  1059. // Desc: Combine axis input from all network players
  1060. //-----------------------------------------------------------------------------
  1061. HRESULT C$$CRoot$$Dlg::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1062. {
  1063.     FLOAT fAxisRotateLRCombined = 0.0f;
  1064.     FLOAT fAxisRotateUDCombined = 0.0f;
  1065.  
  1066.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1067.     // otherwise one of the DirectPlay threads may delete the struct
  1068.     // while this thread is accessing it.
  1069.     PLAYER_LOCK();                  
  1070.  
  1071.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1072.  
  1073.     while( pPlayerInfo != &m_PlayInfoList )
  1074.     {
  1075.         // Use the player whose axis data that is furthest from zero
  1076.         // and if one player is at -1, and another is at +1 then always
  1077.         // choose the positive one.
  1078.         if( fabs(pPlayerInfo->fAxisRotateLR) == fabs(fAxisRotateLRCombined) &&
  1079.                 pPlayerInfo->fAxisRotateLR > 0.0f )
  1080.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1081.         if( fabs(pPlayerInfo->fAxisRotateLR) > fabs(fAxisRotateLRCombined) )
  1082.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1083.  
  1084.         if( fabs(pPlayerInfo->fAxisRotateUD) == fabs(fAxisRotateUDCombined) && 
  1085.                 pPlayerInfo->fAxisRotateUD > 0.0f )
  1086.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1087.         if( fabs(pPlayerInfo->fAxisRotateUD) > fabs(fAxisRotateUDCombined) )
  1088.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1089.  
  1090.         pPlayerInfo = pPlayerInfo->pNext;
  1091.     }
  1092.  
  1093.     // Leave player context CS
  1094.     PLAYER_UNLOCK();           
  1095.     
  1096.     pCombinedUserInput->fAxisRotateLR = fAxisRotateLRCombined;
  1097.     pCombinedUserInput->fAxisRotateUD = fAxisRotateUDCombined;
  1098.  
  1099.     return S_OK;
  1100. }
  1101.  
  1102.  
  1103.  
  1104.  
  1105. $$ELSE // start !ACTIONMAPPER
  1106. //-----------------------------------------------------------------------------
  1107. // Name: CombineInputFromAllPlayers()
  1108. // Desc: Combine axis input from all network players
  1109. //-----------------------------------------------------------------------------
  1110. HRESULT C$$CRoot$$Dlg::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1111. {
  1112.     pCombinedUserInput->bRotateUp    = FALSE;
  1113.     pCombinedUserInput->bRotateDown  = FALSE;
  1114.     pCombinedUserInput->bRotateLeft  = FALSE;
  1115.     pCombinedUserInput->bRotateRight = FALSE;
  1116.  
  1117.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1118.     // otherwise one of the DirectPlay threads may delete the struct
  1119.     // while this thread is accessing it.
  1120.     PLAYER_LOCK();                  
  1121.  
  1122.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1123.  
  1124.     while( pPlayerInfo != &m_PlayInfoList )
  1125.     {
  1126.         // Use the player whose axis data that is furthest from zero
  1127.         // and if one player is at -1, and another is at +1 then always
  1128.         // choose the positive one.
  1129.         if( pPlayerInfo->bRotateUp )
  1130.             pCombinedUserInput->bRotateUp = TRUE;
  1131.         if( pPlayerInfo->bRotateDown )
  1132.             pCombinedUserInput->bRotateDown = TRUE;
  1133.         if( pPlayerInfo->bRotateLeft )
  1134.             pCombinedUserInput->bRotateLeft = TRUE;
  1135.         if( pPlayerInfo->bRotateRight )
  1136.             pCombinedUserInput->bRotateRight = TRUE;
  1137.  
  1138.         pPlayerInfo = pPlayerInfo->pNext;
  1139.     }
  1140.  
  1141.     // Leave player context CS
  1142.     PLAYER_UNLOCK();           
  1143.     
  1144.     return S_OK;
  1145. }
  1146.  
  1147.  
  1148.  
  1149.  
  1150. $$ENDIF // end ACTIONMAPPER
  1151. $$ENDIF // end DPLAY
  1152. $$IF(DPLAYVOICE)
  1153. //-----------------------------------------------------------------------------
  1154. // Name: UpdateTalkingVariables()
  1155. // Desc: Update m_bNetworkPlayersTalking and m_bLocalPlayerTalking
  1156. //-----------------------------------------------------------------------------
  1157. VOID C$$CRoot$$Dlg::UpdateTalkingVariables()
  1158. {
  1159.     // Enter player critical section before accessing player's state data 
  1160.     // otherwise the DirectPlay network threads may change the data
  1161.     // while this thread is accessing it.
  1162.     PLAYER_LOCK();      
  1163.  
  1164.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1165.  
  1166.     m_bNetworkPlayersTalking = FALSE;
  1167.     while( pPlayerInfo != &m_PlayInfoList )
  1168.     {
  1169.         // If any player besides the local player is talking, then set
  1170.         // m_bNetworkPlayersTalking to TRUE
  1171.         if( pPlayerInfo != m_pLocalPlayerInfo && pPlayerInfo->bTalking )
  1172.             m_bNetworkPlayersTalking = TRUE;
  1173.  
  1174.         pPlayerInfo = pPlayerInfo->pNext;
  1175.     }
  1176.  
  1177.     // Update m_bLocalPlayerTalking
  1178.     m_bLocalPlayerTalking = m_pLocalPlayerInfo->bTalking;
  1179.  
  1180.     PLAYER_UNLOCK();                
  1181. }
  1182.  
  1183.  
  1184.  
  1185.  
  1186. $$ENDIF // DPLAYVOICE
  1187. //-----------------------------------------------------------------------------
  1188. // Name: Render()
  1189. // Desc: Called once per frame, the call is the entry point for rendering the 
  1190. //       world.
  1191. //-----------------------------------------------------------------------------
  1192. HRESULT C$$CRoot$$Dlg::Render()
  1193. {
  1194.     // TODO: render world
  1195.  
  1196.     static COLORREF clrNormal  = RGB(255,255,0);
  1197. $$IF(DPLAY)
  1198.     static COLORREF clrWarning = RGB(0,255,255);
  1199. $$ENDIF
  1200.     TCHAR       szMsg[MAX_PATH] = TEXT("");
  1201.     int nCurLineID = IDC_OUTPUT_LINE1 - 1;
  1202.  
  1203. $$IF(DPLAY)
  1204. $$IF(ACTIONMAPPER)
  1205. $$// ******************************************************
  1206.     sprintf( szMsg, TEXT("Network Combined L/R Axis: %0.2f U/D Axis: %0.2f "), 
  1207.               m_CombinedNetworkInput.fAxisRotateLR, m_CombinedNetworkInput.fAxisRotateUD );
  1208. $$// ------------------------------------------------------
  1209.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1210. $$// ------------------------------------------------------
  1211.  
  1212. $$ELSE // start !ACTIONMAPPER
  1213. $$// ******************************************************
  1214.     wsprintf( szMsg, TEXT("Network Combined Keys: U=%d D=%d L=%d R=%d"), 
  1215.               m_CombinedNetworkInput.bRotateUp, m_CombinedNetworkInput.bRotateDown, m_CombinedNetworkInput.bRotateLeft, m_CombinedNetworkInput.bRotateRight );
  1216. $$// ------------------------------------------------------
  1217.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1218. $$// ------------------------------------------------------
  1219.  
  1220. $$ENDIF // ACTIONMAPPER
  1221. $$ENDIF // DPLAY
  1222. $$IF(ACTIONMAPPER)
  1223. $$// ******************************************************
  1224. $$IF(DPLAY)
  1225.     sprintf( szMsg, TEXT("Local Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1226.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1227. $$ELSE
  1228.     sprintf( szMsg, TEXT("Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1229.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1230. $$ENDIF
  1231. $$// ------------------------------------------------------
  1232.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1233. $$// ------------------------------------------------------
  1234.  
  1235. $$ELSE // start !ACTIONMAPPER
  1236. $$IF(DPLAY)
  1237. $$// ******************************************************
  1238.     wsprintf( szMsg, TEXT("Local Arrow keys: U=%d D=%d L=%d R=%d"), 
  1239.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1240. $$ELSE // DPLAY
  1241.     wsprintf( szMsg, TEXT("Arrow keys: Up=%d Down=%d Left=%d Right=%d"), 
  1242.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1243. $$ENDIF // DPLAY
  1244. $$// ------------------------------------------------------
  1245.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1246. $$// ------------------------------------------------------
  1247.  
  1248. $$ENDIF // ACTIONMAPPER
  1249. $$IF(DPLAY)
  1250. $$// ******************************************************
  1251.     sprintf( szMsg, TEXT("%d player(s) in session %s"), 
  1252.                         m_lNumberOfActivePlayers, 
  1253.                         m_pNetConnectWizard->IsHostPlayer() ? TEXT("(Hosting)") : TEXT("") );
  1254. $$// ------------------------------------------------------
  1255.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1256. $$// ------------------------------------------------------
  1257.  
  1258. $$ENDIF // DPLAY
  1259. $$IF(DPLAYVOICE)
  1260. $$// ******************************************************
  1261.     sprintf( szMsg, TEXT("Local Player: %s  Network Players: %s"), 
  1262.                         m_bLocalPlayerTalking ? TEXT("Talking") : TEXT("Silent"), 
  1263.                         m_bNetworkPlayersTalking ? TEXT("Talking") : TEXT("Silent") );
  1264. $$// ------------------------------------------------------
  1265.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1266. $$// ------------------------------------------------------
  1267.  
  1268. $$ENDIF // DPLAYVOICE
  1269. $$IF(!SHOW_TRIANGLE)
  1270. $$IF(!SHOW_TEAPOT)
  1271. $$// ******************************************************
  1272.     sprintf( szMsg, TEXT("World State: %0.3f, %0.3f"), 
  1273.                     m_fWorldRotX, m_fWorldRotY );
  1274. $$// ------------------------------------------------------
  1275.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1276. $$// ------------------------------------------------------
  1277.  
  1278. $$ENDIF // !SHOW_TEAPOT
  1279. $$ENDIF // !SHOW_TRIANGLE
  1280. $$IF(SHOW_TRIANGLE || SHOW_TEAPOT)
  1281. $$IF(ACTIONMAPPER)
  1282. $$// ******************************************************
  1283.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to rotate object") );
  1284. $$// ------------------------------------------------------
  1285.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1286. $$// ------------------------------------------------------
  1287.  
  1288. $$ELSE // start !ACTIONMAPPER
  1289. $$// ******************************************************
  1290.     lstrcpy( szMsg, TEXT("Use arrow keys to rotate object") );
  1291. $$// ------------------------------------------------------
  1292.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1293. $$// ------------------------------------------------------
  1294.  
  1295. $$ENDIF // ACTIONMAPPER
  1296. $$ELSE // start !(SHOW_TRIANGLE || SHOW_TEAPOT)
  1297. $$IF(ACTIONMAPPER)
  1298. $$// ******************************************************
  1299.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to update input") );
  1300. $$// ------------------------------------------------------
  1301.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1302. $$// ------------------------------------------------------
  1303.  
  1304. $$ELSE // start !ACTIONMAPPER
  1305.     lstrcpy( szMsg, TEXT("Use arrow keys to update input") );
  1306. $$// ------------------------------------------------------
  1307.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1308. $$// ------------------------------------------------------
  1309.  
  1310. $$ENDIF // ACTIONMAPPER
  1311. $$ENDIF // SHOW_TRIANGLE || SHOW_TEAPOT
  1312. $$IF(DMUSIC || DSOUND)
  1313. $$// ******************************************************
  1314.     lstrcpy( szMsg, TEXT("Hold 'F5' down to play and repeat a sound") );
  1315. $$// ------------------------------------------------------
  1316.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1317. $$// ------------------------------------------------------
  1318.  
  1319. $$ENDIF // DMUSIC || DSOUND
  1320. $$IF(DPLAYVOICE)
  1321. $$// ******************************************************
  1322.     lstrcpy( szMsg, TEXT("Press 'F4' to configure voice") );
  1323. $$// ------------------------------------------------------
  1324.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1325. $$// ------------------------------------------------------
  1326.  
  1327. $$ENDIF // DPLAYVOICE
  1328. $$IF(ACTIONMAPPER)
  1329. $$// ******************************************************
  1330.     lstrcpy( szMsg, TEXT("Press 'F3' to configure input") );
  1331. $$// ------------------------------------------------------
  1332.     nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1333. $$// ------------------------------------------------------
  1334.  
  1335. $$ENDIF // ACTIONMAPPER
  1336. $$IF(DPLAY)
  1337.     if( m_bHostPausing )
  1338.     {
  1339. $$// ******************************************************
  1340.         lstrcpy( szMsg, TEXT("Paused waiting for host...") );
  1341. $$// ------------------------------------------------------
  1342.         nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1343. $$// ------------------------------------------------------   
  1344.     }
  1345.     else
  1346.     {
  1347. $$// ******************************************************
  1348.         lstrcpy( szMsg, TEXT("") );
  1349. $$// ------------------------------------------------------
  1350.         nCurLineID++; GetDlgItem(nCurLineID)->SetWindowText( szMsg );
  1351. $$// ------------------------------------------------------   
  1352.     }
  1353.  
  1354. $$ENDIF // end DPLAY
  1355.     return S_OK;
  1356. }
  1357.  
  1358.  
  1359.  
  1360.  
  1361. //-----------------------------------------------------------------------------
  1362. // Name: WindowProc()
  1363. // Desc: Callback for all Windows messages
  1364. //-----------------------------------------------------------------------------
  1365. LRESULT C$$CRoot$$Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  1366. {
  1367.     switch( message )
  1368.     {
  1369.         // TODO: Repond to Windows messages as needed
  1370.  
  1371.         case WM_COMMAND:
  1372.         {
  1373.             switch( LOWORD(wParam) )
  1374.             {
  1375.                 case IDCANCEL:
  1376.                 case IDM_EXIT:
  1377.                     PostQuitMessage( 0 );
  1378.                     break;
  1379.  
  1380. $$IF(ACTIONMAPPER)
  1381.                 case IDM_CONFIGINPUT:
  1382.                     m_UserInput.bDoConfigureInput = TRUE;
  1383.                     break;
  1384. $$ENDIF 
  1385. $$IF(DPLAYVOICE)
  1386.  
  1387.                 case IDM_CONFIGVOICE:
  1388.                     m_UserInput.bDoConfigureVoice = TRUE;
  1389.                     break;
  1390. $$ENDIF
  1391.             }
  1392.             break;
  1393.         }
  1394.  
  1395.         case WM_ACTIVATEAPP:
  1396.             m_bHasFocus = wParam;
  1397.             break;
  1398.  
  1399.         case WM_ENTERSIZEMOVE:
  1400.         case WM_ENTERMENULOOP:
  1401.             // Halt frame movement while the app is sizing or moving
  1402.             // or when menus are displayed
  1403.             Pause( TRUE );
  1404.             break;
  1405.  
  1406.         case WM_EXITSIZEMOVE:
  1407.         case WM_EXITMENULOOP:
  1408.             Pause( FALSE );
  1409.             break;
  1410.     }
  1411.  
  1412.     return CDialog::WindowProc(message, wParam, lParam);
  1413. }
  1414.  
  1415.  
  1416.  
  1417.  
  1418. //-----------------------------------------------------------------------------
  1419. // Name: Pause()
  1420. // Desc: Called in to toggle the pause state of the app.
  1421. //-----------------------------------------------------------------------------
  1422. VOID C$$CRoot$$Dlg::Pause( BOOL bPause )
  1423. {
  1424.     static DWORD dwAppPausedCount = 0L;
  1425.  
  1426. $$IF(DPLAY)
  1427.     // Tell the other apps to pause or unpause if this is the host
  1428.     if( m_pNetConnectWizard && m_pNetConnectWizard->IsHostPlayer() )
  1429.         SendPauseMessageToAll( bPause );
  1430.  
  1431. $$ENDIF
  1432. $$IF(ACTIONMAPPER)
  1433.     // Get access to the list of semantically-mapped input devices
  1434.     // to zero the state of all InputDeviceState structs.  This is needed
  1435.     // because when using DISCL_FOREGROUND, the action mapper will not 
  1436.     // record actions when the focus switches, for example if a dialog appears.
  1437.     // This causes a problem when a button held down when loosing focus, and let
  1438.     // go when the focus is lost.  The app will not record that the button 
  1439.     // has been let go, so the state will be incorrect when focus returns.  
  1440.     // To fix this either use DISCL_BACKGROUND or zero the state when 
  1441.     // loosing focus.
  1442.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1443.     DWORD dwNumDevices;
  1444.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1445.  
  1446.     for( DWORD i=0; i<dwNumDevices; i++ )
  1447.     {
  1448.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1449.         ZeroMemory( pInputDeviceState, sizeof(InputDeviceState) );
  1450.     }
  1451.  
  1452. $$ENDIF
  1453.     dwAppPausedCount += ( bPause ? +1 : -1 );
  1454.  
  1455.     // Handle the first pause request (of many, nestable pause requests)
  1456.     if( bPause && ( 1 == dwAppPausedCount ) )
  1457.     {
  1458.         // Stop the scene from animating
  1459.         DXUtil_Timer( TIMER_STOP );
  1460.     }
  1461.  
  1462.     if( 0 == dwAppPausedCount )
  1463.     {
  1464.         // Restart the timers
  1465.         DXUtil_Timer( TIMER_START );
  1466.     }
  1467. }
  1468.  
  1469.  
  1470.  
  1471.  
  1472. $$IF(DPLAYVOICE)
  1473. //-----------------------------------------------------------------------------
  1474. // Name: UserConfigVoice()
  1475. // Desc: Allow user to configure the voice settings
  1476. //-----------------------------------------------------------------------------
  1477. HRESULT C$$CRoot$$Dlg::UserConfigVoice()
  1478. {
  1479.     HRESULT hr;
  1480.    
  1481.     // Configure the voice settings, store the settings in 
  1482.     // m_guidDVSessionCT & m_dvClientConfig
  1483.     if( m_pNetVoice )
  1484.     {
  1485.         hr = m_pNetVoice->DoVoiceSetupDialog( AfxGetInstanceHandle(), m_hWnd, &m_guidDVSessionCT, &m_dvClientConfig );
  1486.  
  1487.         // If the settings dialog was not canceled, then change the settings
  1488.         if( hr != DVERR_USERCANCEL )
  1489.             m_pNetVoice->ChangeVoiceClientSettings( &m_dvClientConfig );
  1490.     }
  1491.  
  1492.     return S_OK;
  1493. }
  1494.  
  1495.  
  1496.  
  1497.  
  1498. $$ENDIF
  1499. //-----------------------------------------------------------------------------
  1500. // Name: FinalCleanup()
  1501. // Desc: Called before the app exits, this function gives the app the chance
  1502. //       to cleanup after itself.
  1503. //-----------------------------------------------------------------------------
  1504. HRESULT C$$CRoot$$Dlg::FinalCleanup()
  1505. {
  1506.     // TODO: Perform any final cleanup needed
  1507. $$IF(DINPUT)
  1508.     // Cleanup DirectInput
  1509.     CleanupDirectInput();
  1510.  
  1511. $$ENDIF
  1512. $$IF(DMUSIC || DSOUND)
  1513.     // Cleanup DirectX audio objects
  1514.     SAFE_DELETE( m_pBounceSound );
  1515. $$IF(DMUSIC)
  1516.     SAFE_DELETE( m_pMusicManager );
  1517. $$ELSE // start !DMUSIC
  1518.     SAFE_DELETE( m_pSoundManager );
  1519. $$ENDIF // end DMUSIC
  1520.  
  1521. $$ENDIF // end (DMUSIC || DSOUND)
  1522. $$IF(DPLAY)
  1523.     // Cleanup DirectPlay
  1524.     CleanupDirectPlay();
  1525.  
  1526.     // Cleanup COM
  1527.     CoUninitialize();
  1528.  
  1529. $$ENDIF
  1530.     // Write the settings to the registry
  1531.     WriteSettings();
  1532.  
  1533.     return S_OK;
  1534. }
  1535.  
  1536.  
  1537.  
  1538.  
  1539. $$IF(DPLAY)
  1540. //-----------------------------------------------------------------------------
  1541. // Name: CleanupDirectPlay()
  1542. // Desc: Cleanup DirectPlay 
  1543. //-----------------------------------------------------------------------------
  1544. VOID C$$CRoot$$Dlg::CleanupDirectPlay()
  1545. {
  1546. $$IF(DPLAYVOICE)
  1547.     // Disconnect from the DirectPlayVoice session, 
  1548.     // and destroy it if we are the host player.
  1549.     SAFE_DELETE( m_pNetVoice ); 
  1550.  
  1551. $$ENDIF
  1552.     // Cleanup DirectPlay and helper classes
  1553.     if( m_pNetConnectWizard )
  1554.         m_pNetConnectWizard->Shutdown();
  1555.  
  1556.     if( m_pDP )
  1557.     {
  1558.         m_pDP->Close(0);
  1559.         SAFE_RELEASE( m_pDP );
  1560.     }
  1561.  
  1562.     if( m_pLobbiedApp )
  1563.     {
  1564.         m_pLobbiedApp->Close( 0 );
  1565.         SAFE_RELEASE( m_pLobbiedApp );
  1566.     }    
  1567.  
  1568.     PLAYER_LOCK();                  // enter player context CS
  1569.     PLAYER_RELEASE( m_pLocalPlayerInfo ); // Release player and cleanup if needed
  1570.     PLAYER_UNLOCK();                // leave player context CS
  1571.  
  1572.     // Don't delete the wizard until we know that 
  1573.     // DirectPlay is out of its message handlers.
  1574.     // This will be true after Close() has been called. 
  1575.     SAFE_DELETE( m_pNetConnectWizard );
  1576.     DeleteCriticalSection( &g_csPlayerContext );
  1577.     DeleteCriticalSection( &g_csWorldStateContext );
  1578.  
  1579.     if( m_hrNet == DPNERR_CONNECTIONLOST )
  1580.     {
  1581.         MessageBox( TEXT("The DirectPlay session was lost. ")
  1582.                     TEXT("The sample will now quit."),
  1583.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  1584.     }
  1585. }
  1586.  
  1587.  
  1588.  
  1589. $$ENDIF
  1590. $$IF(DINPUT)
  1591. //-----------------------------------------------------------------------------
  1592. // Name: CleanupDirectInput()
  1593. // Desc: Cleanup DirectInput 
  1594. //-----------------------------------------------------------------------------
  1595. VOID C$$CRoot$$Dlg::CleanupDirectInput()
  1596. {
  1597. $$IF(KEYBOARD)
  1598.     // Cleanup DirectX input objects
  1599.     SAFE_RELEASE( m_pKeyboard );
  1600.     SAFE_RELEASE( m_pDI );
  1601. $$ENDIF
  1602. $$IF(ACTIONMAPPER)
  1603.     if( NULL == m_pInputDeviceManager )
  1604.         return;
  1605.  
  1606.     // Get access to the list of semantically-mapped input devices
  1607.     // to delete all InputDeviceState structs
  1608.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1609.     DWORD dwNumDevices;
  1610.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1611.  
  1612.     for( DWORD i=0; i<dwNumDevices; i++ )
  1613.     {
  1614.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1615.         SAFE_DELETE( pInputDeviceState );
  1616.         pDeviceInfos[i].pParam = NULL;
  1617.     }
  1618.  
  1619.     // Cleanup DirectX input objects
  1620.     SAFE_DELETE( m_pInputDeviceManager );
  1621. $$ENDIF
  1622. }
  1623.  
  1624.  
  1625.  
  1626.  
  1627. $$ENDIF
  1628. $$IF(DPLAY)
  1629. //-----------------------------------------------------------------------------
  1630. // Name: StaticDirectPlayMessageHandler
  1631. // Desc: Static callback helper to call into C$$CRoot$$Dlg class
  1632. //-----------------------------------------------------------------------------
  1633. HRESULT WINAPI C$$CRoot$$Dlg::StaticDirectPlayMessageHandler( PVOID pvUserContext, 
  1634.                                                                   DWORD dwMessageId, 
  1635.                                                                   PVOID pMsgBuffer )
  1636. {
  1637.     if( g_pDlg )
  1638.         return g_pDlg->DirectPlayMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1639.     return S_OK;
  1640. }
  1641.  
  1642.  
  1643.  
  1644.  
  1645. //-----------------------------------------------------------------------------
  1646. // Name: DirectPlayMessageHandler
  1647. // Desc: Handler for DirectPlay messages.  This function is called by
  1648. //       the DirectPlay message handler pool of threads, so be careful of thread
  1649. //       synchronization problems with shared memory
  1650. //-----------------------------------------------------------------------------
  1651. HRESULT C$$CRoot$$Dlg::DirectPlayMessageHandler( PVOID pvUserContext, 
  1652.                                                      DWORD dwMessageId, 
  1653.                                                      PVOID pMsgBuffer )
  1654. {
  1655.     // Try not to stay in this message handler for too long, otherwise
  1656.     // there will be a backlog of data.  The best solution is to 
  1657.     // queue data as it comes in, and then handle it on other threads.
  1658.     
  1659.     // This function is called by the DirectPlay message handler pool of 
  1660.     // threads, so be careful of thread synchronization problems with shared memory
  1661.  
  1662.     switch( dwMessageId )
  1663.     {
  1664.         case DPN_MSGID_CREATE_PLAYER:
  1665.         {
  1666.             HRESULT hr;
  1667.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  1668.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  1669.  
  1670.             // Get the peer info and extract its name
  1671.             DWORD dwSize = 0;
  1672.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  1673.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  1674.                                      pdpPlayerInfo, &dwSize, 0 );
  1675.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  1676.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1677.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  1678.             ZeroMemory( pdpPlayerInfo, dwSize );
  1679.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  1680.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  1681.                                      pdpPlayerInfo, &dwSize, 0 );
  1682.             if( FAILED(hr) )
  1683.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  1684.  
  1685.             // Create a new and fill in a APP_PLAYER_INFO
  1686.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  1687.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  1688.             pPlayerInfo->lRefCount   = 1;
  1689.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  1690.  
  1691.             // This stores a extra TCHAR copy of the player name for 
  1692.             // easier access.  This will be redundant copy since DPlay 
  1693.             // also keeps a copy of the player name in GetPeerInfo()
  1694.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  1695.                                                pdpPlayerInfo->pwszName, MAX_PATH );
  1696.  
  1697.             if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  1698.             {
  1699.                 m_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer;
  1700.                 m_pLocalPlayerInfo = pPlayerInfo;
  1701.  
  1702.                 // Increase the ref if this is the local player, so the struct 
  1703.                 // won't be deleted when DirectPlay shuts down.  The
  1704.                 // main window thread will release the struct when it is done
  1705.                 pPlayerInfo->lRefCount++;
  1706.             }
  1707.             else
  1708.             {
  1709.                 if( m_pNetConnectWizard->IsHostPlayer() )
  1710.                 {
  1711.                     // If the local player is the host and 
  1712.                     // this DPN_MSGID_CREATE_PLAYER is not for the local player
  1713.                     // then set the m_fWorldSyncTimer to fire immediately so
  1714.                     // the new player will get the state of the world
  1715.                     m_fWorldSyncTimer = 0.0f;
  1716.                 }
  1717.             }
  1718.  
  1719.             // Add the APP_PLAYER_INFO to the circular linked list, m_PlayInfoList
  1720.             pPlayerInfo->pNext = m_PlayInfoList.pNext;
  1721.             pPlayerInfo->pPrev = &m_PlayInfoList;
  1722.             m_PlayInfoList.pNext->pPrev = pPlayerInfo;    
  1723.             m_PlayInfoList.pNext = pPlayerInfo;    
  1724.  
  1725.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  1726.  
  1727.             // Tell DirectPlay to store this pPlayerInfo 
  1728.             // pointer in the pvPlayerContext.
  1729.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  1730.  
  1731.             // Update the number of active players, and if the app needs to 
  1732.             // tell the UI immediately about this, then post a message to 
  1733.             // the window thread.  This keeps the DirectPlay message handler 
  1734.             // from blocking
  1735.             InterlockedIncrement( &m_lNumberOfActivePlayers );
  1736.             break;
  1737.         }
  1738.  
  1739.         case DPN_MSGID_RECEIVE:
  1740.         {
  1741.             PDPNMSG_RECEIVE pReceiveMsg;
  1742.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  1743.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  1744.  
  1745.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  1746.             switch( pMsg->nType )
  1747.             {
  1748.                 case GAME_MSGID_INPUTSTATE:
  1749.                 {
  1750.                     // Update the APP_PLAYER_INFO struct associated with this
  1751.                     // network player with the data send in the GAMEMSG_INPUTSTATE.
  1752.                     GAMEMSG_INPUTSTATE* pInputStateMsg = (GAMEMSG_INPUTSTATE*) pMsg;
  1753.  
  1754.                     // Enter player critical section before accessing player's state data 
  1755.                     // otherwise the main thread or other DirectPlay threads may access the data
  1756.                     // while this thread is changing it.
  1757.                     PLAYER_LOCK();                  
  1758.  
  1759. $$IF(ACTIONMAPPER)
  1760.                     pPlayerInfo->fAxisRotateLR = pInputStateMsg->fAxisRotateLR;
  1761.                     pPlayerInfo->fAxisRotateUD = pInputStateMsg->fAxisRotateUD;
  1762. $$ELSE
  1763.                     pPlayerInfo->bRotateUp    = pInputStateMsg->bRotateUp;
  1764.                     pPlayerInfo->bRotateDown  = pInputStateMsg->bRotateDown;
  1765.                     pPlayerInfo->bRotateLeft  = pInputStateMsg->bRotateLeft;
  1766.                     pPlayerInfo->bRotateRight = pInputStateMsg->bRotateRight;
  1767. $$ENDIF
  1768.  
  1769.                     PLAYER_UNLOCK();                // leave player context CS
  1770.                     break;
  1771.                 }
  1772.  
  1773.                 case GAME_MSGID_WORLDSTATE:
  1774.                 {
  1775.                     // Enter world state critical section before accessing world state data 
  1776.                     // otherwise the main thread or other DirectPlay threads may access the data
  1777.                     // while this thread is changing it.
  1778.                     WORLD_LOCK();
  1779.  
  1780.                     // Update the world state with the data from GAMEMSG_WORLDSTATE
  1781.                     GAMEMSG_WORLDSTATE* pMsgWorldState = (GAMEMSG_WORLDSTATE*) pMsg;
  1782.                     m_fWorldRotX = pMsgWorldState->fWorldRotX;
  1783.                     m_fWorldRotY = pMsgWorldState->fWorldRotY;
  1784.  
  1785.                     // Leave the critical section
  1786.                     WORLD_UNLOCK();
  1787.                     break;
  1788.                 }
  1789.  
  1790.                 case GAME_MSGID_HOSTPAUSE:
  1791.                 {
  1792.                     GAMEMSG_HOSTPAUSE* pMsgPause = (GAMEMSG_HOSTPAUSE*) pMsg;
  1793.  
  1794.                     // Update the pause state with the data from GAMEMSG_HOSTPAUSE
  1795.                     m_bHostPausing = pMsgPause->bHostPause;
  1796.                     break;
  1797.                 }
  1798.             }
  1799.             break;
  1800.         }
  1801.  
  1802.         case DPN_MSGID_DESTROY_PLAYER:
  1803.         {
  1804.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  1805.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  1806.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  1807.  
  1808.             PLAYER_LOCK();                  // enter player context CS
  1809.  
  1810.             // Remove pPlayerInfo from the circular linked list
  1811.             pPlayerInfo->pNext->pPrev = pPlayerInfo->pPrev;
  1812.             pPlayerInfo->pPrev->pNext = pPlayerInfo->pNext;
  1813.  
  1814.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  1815.             PLAYER_UNLOCK();                // leave player context CS
  1816.  
  1817.             // Update the number of active players, and if the app needs to 
  1818.             // tell the UI immediately about this, then post a message to 
  1819.             // the window thread.  This keeps the DirectPlay message handler 
  1820.             // from blocking
  1821.             InterlockedDecrement( &m_lNumberOfActivePlayers );
  1822.             break;
  1823.         }
  1824.  
  1825.         case DPN_MSGID_TERMINATE_SESSION:
  1826.         {
  1827.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  1828.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  1829.  
  1830.             m_hrNet = DPNERR_CONNECTIONLOST;
  1831.  
  1832.             // Close the window, which shuts down the app
  1833.             if( m_hWnd )
  1834.                 PostMessage( WM_QUIT, 0, 0 );
  1835.             break;
  1836.         }
  1837.     }
  1838.  
  1839.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1840.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  1841.     if( m_pNetConnectWizard )
  1842.         return m_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, 
  1843.                                                     pMsgBuffer );
  1844.     
  1845.     return S_OK;
  1846. }
  1847.  
  1848.  
  1849.  
  1850.  
  1851. //-----------------------------------------------------------------------------
  1852. // Name: StaticDirectPlayLobbyMessageHandler
  1853. // Desc: Static callback helper to call into C$$CRoot$$Dlg class
  1854. //-----------------------------------------------------------------------------
  1855. HRESULT WINAPI C$$CRoot$$Dlg::StaticDirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  1856.                                                                   DWORD dwMessageId, 
  1857.                                                                   PVOID pMsgBuffer )
  1858. {
  1859.     if( g_pDlg )
  1860.         return g_pDlg->DirectPlayLobbyMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1861.     return S_OK;
  1862. }
  1863.  
  1864.  
  1865.  
  1866.  
  1867. //-----------------------------------------------------------------------------
  1868. // Name: DirectPlayLobbyMessageHandler
  1869. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  1870. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  1871. //       thread synchronization problems with shared memory
  1872. //-----------------------------------------------------------------------------
  1873. HRESULT C$$CRoot$$Dlg::DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  1874.                                                           DWORD dwMessageId, 
  1875.                                                           PVOID pMsgBuffer )
  1876. {
  1877.     switch( dwMessageId )
  1878.     {
  1879.         case DPL_MSGID_CONNECT:
  1880.         {
  1881.             PDPL_MESSAGE_CONNECT pConnectMsg;
  1882.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  1883.  
  1884.             // The CNetConnectWizard will handle this message for us,
  1885.             // so there is nothing we need to do here for this simple
  1886.             // sample.
  1887.             break;
  1888.         }
  1889.  
  1890.         case DPL_MSGID_DISCONNECT:
  1891.         {
  1892.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  1893.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  1894.  
  1895.             // We should free any data associated with the lobby 
  1896.             // client here, but there is none.
  1897.             break;
  1898.         }
  1899.  
  1900.         case DPL_MSGID_RECEIVE:
  1901.         {
  1902.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  1903.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  1904.  
  1905.             // The lobby client sent us data.  This sample doesn't
  1906.             // expected data from the client, but it is useful 
  1907.             // for more complex apps.
  1908.             break;
  1909.         }
  1910.  
  1911.         case DPL_MSGID_CONNECTION_SETTINGS:
  1912.         {
  1913.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  1914.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  1915.  
  1916.             // The lobby client has changed the connection settings.  
  1917.             // This simple sample doesn't handle this, but more complex apps may
  1918.             // want to.
  1919.             break;
  1920.         }
  1921.     }
  1922.  
  1923.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  1924.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  1925.     if( m_pNetConnectWizard )
  1926.         return m_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  1927.                                                          pMsgBuffer );
  1928.     
  1929.     return S_OK;
  1930. }
  1931.  
  1932.  
  1933.  
  1934.  
  1935. $$ENDIF
  1936. $$IF(DPLAYVOICE)
  1937. //-----------------------------------------------------------------------------
  1938. // Name: StaticDirectPlayVoiceServerMessageHandler
  1939. // Desc: Static callback helper to call into C$$CRoot$$Dlg class
  1940. //-----------------------------------------------------------------------------
  1941. HRESULT WINAPI C$$CRoot$$Dlg::StaticDirectPlayVoiceServerMessageHandler( PVOID pvUserContext, 
  1942.                                                                   DWORD dwMessageId, 
  1943.                                                                   PVOID pMsgBuffer )
  1944. {
  1945.     if( g_pDlg )
  1946.         return g_pDlg->DirectPlayVoiceServerMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1947.     return S_OK;
  1948. }
  1949.  
  1950.  
  1951.  
  1952.  
  1953. //-----------------------------------------------------------------------------
  1954. // Name: DirectPlayVoiceServerMessageHandler()
  1955. // Desc: The callback for DirectPlayVoice server messages.  
  1956. //-----------------------------------------------------------------------------
  1957. HRESULT C$$CRoot$$Dlg::DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1958.                                                                 LPVOID lpMessage )
  1959. {
  1960.     // This simple sample doesn't respond to any server messages
  1961.     return S_OK;
  1962. }
  1963.  
  1964.  
  1965.  
  1966.  
  1967. //-----------------------------------------------------------------------------
  1968. // Name: StaticDirectPlayVoiceClientMessageHandler
  1969. // Desc: Static callback helper to call into C$$CRoot$$Dlg class
  1970. //-----------------------------------------------------------------------------
  1971. HRESULT WINAPI C$$CRoot$$Dlg::StaticDirectPlayVoiceClientMessageHandler( PVOID pvUserContext, 
  1972.                                                                   DWORD dwMessageId, 
  1973.                                                                   PVOID pMsgBuffer )
  1974. {
  1975.     if( g_pDlg )
  1976.         return g_pDlg->DirectPlayVoiceClientMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  1977.     return S_OK;
  1978. }
  1979.  
  1980.  
  1981.  
  1982.  
  1983. //-----------------------------------------------------------------------------
  1984. // Name: DirectPlayVoiceClientMessageHandler()
  1985. // Desc: The callback for DirectPlayVoice client messages.  
  1986. //       This handles client messages and updates the UI the whenever a client 
  1987. //       starts or stops talking.  
  1988. //-----------------------------------------------------------------------------
  1989. HRESULT C$$CRoot$$Dlg::DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  1990.                                                                 LPVOID lpMessage )
  1991. {
  1992.     // Try not to stay in this message handler for too long, otherwise
  1993.     // there will be a backlog of data.  The best solution is to 
  1994.     // queue data as it comes in, and then handle it on other threads.
  1995.     
  1996.     // This function is called by the DirectPlay message handler pool of 
  1997.     // threads, so be care of thread synchronization problems with shared memory
  1998.  
  1999.     HRESULT hr;
  2000.     HWND hDlg = (HWND) lpvUserContext;
  2001.  
  2002.     switch( dwMessageType )
  2003.     {
  2004.         case DVMSGID_CREATEVOICEPLAYER:
  2005.         {
  2006.             DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  2007.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  2008.  
  2009.             // Enter player critical section before accessing player's state data 
  2010.             // otherwise the main thread or other DirectPlay threads may access the data
  2011.             // while this thread is changing it.
  2012.             PLAYER_LOCK(); 
  2013.  
  2014.             // Get the player context associated with this DPNID
  2015.             hr = m_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  2016.                                           (LPVOID* const) &pPlayerInfo, 0);
  2017.  
  2018.             if( FAILED(hr) || pPlayerInfo == NULL )
  2019.             {
  2020.                 // The player who sent this may have gone away before this 
  2021.                 // message was handled, so just ignore it
  2022.                 PLAYER_UNLOCK();
  2023.                 break;
  2024.             }
  2025.  
  2026.             // Addref player struct, so it can used freely by the voice layer
  2027.             PLAYER_ADDREF( pPlayerInfo ); 
  2028.  
  2029.             pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  2030.  
  2031.             PLAYER_UNLOCK(); // leave player context CS
  2032.  
  2033.             // Set voice context value
  2034.             pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  2035.  
  2036.             // We're leaving the extra reference, so the voice layer will 
  2037.             // own that reference
  2038.             break;
  2039.         }
  2040.  
  2041.         case DVMSGID_DELETEVOICEPLAYER:
  2042.         {
  2043.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  2044.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2045.  
  2046.             // Release our extra reference on the player info that we have for the voice
  2047.             // context value.  
  2048.             PLAYER_LOCK();
  2049.             PLAYER_RELEASE( pPlayerInfo );  
  2050.             PLAYER_UNLOCK();
  2051.             break;
  2052.         }            
  2053.  
  2054.         case DVMSGID_RECORDSTART:             
  2055.         { 
  2056.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  2057.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2058.  
  2059.             PLAYER_LOCK();
  2060.             if( pPlayerInfo )
  2061.                 pPlayerInfo->bTalking = TRUE;   
  2062.             PLAYER_UNLOCK();
  2063.             break;
  2064.         }
  2065.  
  2066.         case DVMSGID_RECORDSTOP:             
  2067.         {
  2068.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  2069.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2070.  
  2071.             PLAYER_LOCK();
  2072.             if( pPlayerInfo )
  2073.                 pPlayerInfo->bTalking = FALSE;  
  2074.             PLAYER_UNLOCK();
  2075.             break;
  2076.         }
  2077.  
  2078.         case DVMSGID_PLAYERVOICESTART:
  2079.         {
  2080.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  2081.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2082.  
  2083.             PLAYER_LOCK();
  2084.             if( pPlayerInfo )
  2085.                 pPlayerInfo->bTalking = TRUE;   
  2086.             PLAYER_UNLOCK();
  2087.             break;
  2088.         }
  2089.  
  2090.         case DVMSGID_PLAYERVOICESTOP:
  2091.         {
  2092.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  2093.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2094.  
  2095.             PLAYER_LOCK();
  2096.             if( pPlayerInfo )
  2097.                 pPlayerInfo->bTalking = FALSE;  
  2098.             PLAYER_UNLOCK();
  2099.             break;
  2100.         }
  2101.     }
  2102.  
  2103.     return S_OK;
  2104. }
  2105.  
  2106.  
  2107.  
  2108.  
  2109. $$ENDIF
  2110. //-----------------------------------------------------------------------------
  2111. // Name: C$$CRoot$$App()
  2112. // Desc: Constructor
  2113. //-----------------------------------------------------------------------------
  2114. C$$CRoot$$App::C$$CRoot$$App()
  2115. {
  2116.     m_pDlg = NULL;
  2117. }
  2118.  
  2119.  
  2120.  
  2121.  
  2122. //-----------------------------------------------------------------------------
  2123. // Name: InitInstance()
  2124. // Desc: Inits the app
  2125. //-----------------------------------------------------------------------------
  2126. BOOL C$$CRoot$$App::InitInstance()
  2127. {
  2128. #ifdef _AFXDLL
  2129.     Enable3dControls();         // Call this when using MFC in a shared DLL
  2130. #else
  2131.     Enable3dControlsStatic();   // Call this when linking to MFC statically
  2132. #endif
  2133.  
  2134.     m_pDlg = new C$$CRoot$$Dlg();
  2135.     if( m_pDlg == NULL )
  2136.         return FALSE;
  2137.  
  2138.     m_pDlg->Create( IDD_$$SAFE_ROOT$$_DIALOG );
  2139.     m_pMainWnd = m_pDlg;
  2140.  
  2141.     // Initialize the application timer
  2142.     DXUtil_Timer( TIMER_START );
  2143.  
  2144.     // Initialize the app's custom scene stuff
  2145.     if( FAILED( m_pDlg->OneTimeSceneInit() ) )
  2146.         return FALSE;
  2147.  
  2148.     // Return TRUE to start msg proc
  2149.     return TRUE;
  2150. }
  2151.  
  2152.  
  2153.  
  2154.  
  2155. //-----------------------------------------------------------------------------
  2156. // Name: OnIdle()
  2157. // Desc: Called when messages are not being procesed
  2158. //-----------------------------------------------------------------------------
  2159. BOOL C$$CRoot$$App::OnIdle(LONG lCount) 
  2160. {
  2161.     // Update the time variables
  2162.     m_pDlg->m_fTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  2163.     m_pDlg->m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  2164.  
  2165.     // This app uses idle time processing for the game loop
  2166.     if( FAILED( m_pDlg->FrameMove() ) )
  2167.         PostQuitMessage(0);
  2168.     if( FAILED( m_pDlg->Render() ) ) 
  2169.         PostQuitMessage(0);
  2170.  
  2171.     Sleep( 20 );
  2172.     
  2173.     // Return 1 so it keeps calling OnIdle()
  2174.     return 1; 
  2175. }
  2176.  
  2177.  
  2178.  
  2179.  
  2180. //-----------------------------------------------------------------------------
  2181. // Name: ExitInstance()
  2182. // Desc: Cleanup the app
  2183. //-----------------------------------------------------------------------------
  2184. int C$$CRoot$$App::ExitInstance() 
  2185. {
  2186.     if( m_pDlg )
  2187.         m_pDlg->FinalCleanup();
  2188.     
  2189.     SAFE_DELETE( m_pDlg );
  2190.  
  2191.     return CWinApp::ExitInstance();
  2192. }
  2193.  
  2194.  
  2195.  
  2196.  
  2197. //-----------------------------------------------------------------------------
  2198. // Name: OnInitDialog()
  2199. // Desc: Init the dialog
  2200. //-----------------------------------------------------------------------------
  2201. BOOL C$$CRoot$$Dlg::OnInitDialog()
  2202. {
  2203.     CDialog::OnInitDialog();
  2204.  
  2205.     // Set the icon for this dialog.  The framework does this automatically
  2206.     //  when the application's main window is not a dialog
  2207.     SetIcon(m_hIcon, TRUE);         // Set big icon
  2208.     SetIcon(m_hIcon, FALSE);        // Set small icon
  2209.     
  2210.     GetDlgItem(IDC_OUTPUT_LINE1)->SetWindowText( TEXT("") );
  2211.     GetDlgItem(IDC_OUTPUT_LINE2)->SetWindowText( TEXT("") );
  2212.     GetDlgItem(IDC_OUTPUT_LINE3)->SetWindowText( TEXT("") );
  2213.     GetDlgItem(IDC_OUTPUT_LINE4)->SetWindowText( TEXT("") );
  2214.     GetDlgItem(IDC_OUTPUT_LINE5)->SetWindowText( TEXT("") );
  2215.     GetDlgItem(IDC_OUTPUT_LINE6)->SetWindowText( TEXT("") );
  2216.     GetDlgItem(IDC_OUTPUT_LINE7)->SetWindowText( TEXT("") );
  2217.     GetDlgItem(IDC_OUTPUT_LINE8)->SetWindowText( TEXT("") );
  2218.     GetDlgItem(IDC_OUTPUT_LINE9)->SetWindowText( TEXT("") );
  2219.     GetDlgItem(IDC_OUTPUT_LINE10)->SetWindowText( TEXT("") );
  2220.     GetDlgItem(IDC_OUTPUT_LINE11)->SetWindowText( TEXT("") );
  2221.  
  2222.     // TODO: Add extra initialization here
  2223.     
  2224.     return TRUE;  // return TRUE  unless you set the focus to a control
  2225. }
  2226.  
  2227.  
  2228.  
  2229.  
  2230. //-----------------------------------------------------------------------------
  2231. // Name: DoDataExchange()
  2232. // Desc: MFC dialog data exchange
  2233. //-----------------------------------------------------------------------------
  2234. void C$$CRoot$$Dlg::DoDataExchange(CDataExchange* pDX)
  2235. {
  2236.     CDialog::DoDataExchange(pDX);
  2237.     //{{AFX_DATA_MAP(C$$CRoot$$Dlg)
  2238.         // NOTE: the ClassWizard will add DDX and DDV calls here
  2239.     //}}AFX_DATA_MAP
  2240. }
  2241.  
  2242.  
  2243.  
  2244.  
  2245.  
  2246.